package gviews

import (
	"strings"

	consts "gitee.com/abril-cx/gtools/gconsts"
	log "gitee.com/abril-cx/gtools/glog"
	mongo "gitee.com/abril-cx/gtools/gmongo"
	utils "gitee.com/abril-cx/gtools/gutils"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
)

func getFieldMapList(req_data *RequestData) (map[string]bson.M, []string, error) {
	field_show_list := []string{}
	field_map := map[string]bson.M{}
	field_list, err := GetFieldList(req_data)
	if err != nil {
		log.Error(err)
		return field_map, field_show_list, err
	}
	for _, v := range field_list {
		v_field := v["field"].(string)
		if !v["hidden_depth"].(bool) && v_field != "_id" {
			field_show_list = append(field_show_list, v_field)
		}
		if v["bind"] != nil {
			field_map[v_field] = bson.M{
				"bind":    v["bind"].(string),
				"related": v["related"],
			}
		}
	}
	return field_map, field_show_list, err
}

func getRelatedData(results []bson.M, field_map map[string]bson.M) ([]bson.M, error) {
	// 获取关联数据
	for _, item := range results {
		for k, v := range field_map {
			if item[k] == nil {
				continue
			}
			bind := v["bind"].(string)
			related := v["related"]
			bind_list := strings.Split(bind, ".")
			// 获取关联表数据
			related_result := bson.M{}
			// log.Info(bind_list, consts.APP_NAME_RELATED)
			if bind_list[0] == consts.APP_NAME_RELATED {
				var err error
				if related != nil {
					err = mongo.Conn.Model(bind_list[1]).Select(related.(string)).Filter(bson.M{
						"_id": item[k],
					}).FindOne(&related_result)
				} else {
					err = mongo.Conn.Model(bind_list[1]).Filter(bson.M{
						"_id": item[k],
					}).FindOne(&related_result)
				}
				if err != nil {
					log.Error("getRelatedData 获取关联数据", err)
					return results, err
				}
			} else {
				log.Warning("没写")
				// log.Info(bind_list, consts.APP_NAME_RELATED)
			}
			if related != nil {
				value, ok := related_result[related.(string)]
				if ok {
					item[k] = bson.M{
						"label": value,
						"value": item[k],
					}
				}
			} else {
				item[k] = related_result
			}
		}
	}
	return results, nil
}

func GetInfo(req_data *RequestData) (bson.M, error) {
	result := bson.M{}
	err := mongo.Conn.Model(req_data.Model).Filter(bson.M{
		"_id": req_data.Id,
	}).FindOne(&result)
	if err != nil {
		log.Error("GetInfo 获取信息", err)
		return result, err
	}
	field_map, _, err := getFieldMapList(req_data)
	if err != nil {
		return result, err
	}
	results, err := getRelatedData([]bson.M{result}, field_map)
	if err != nil {
		return result, err
	}
	return results[0], err
}

func GetInfoList(req_data *RequestData) (interface{}, error) {
	result := []bson.M{}
	err := mongo.Conn.Model(req_data.Model).Filter(bson.M{}).Find(&result)
	return result, err
}

func WriteAdd(req_data *RequestData) (interface{}, error) {
	for k, v := range req_data.Maps {
		if strings.HasSuffix(k, "_id") {
			req_data.Maps[k], _ = primitive.ObjectIDFromHex(v.(string))
		}
	}
	result, err := mongo.Conn.Model(req_data.Model).CreateOne(req_data.Maps)
	return result.InsertedID, err
}

func WriteUpdate(req_data *RequestData) error {
	for k, v := range req_data.Maps {
		if strings.HasSuffix(k, "_id") {
			value := v.(string)
			if value == "" {
				req_data.Maps[k] = nil
			} else {
				kk, err := primitive.ObjectIDFromHex(value)
				if err == nil {
					req_data.Maps[k] = kk
				} else {
					req_data.Maps[k] = nil
				}
			}
		}
	}
	_, err := mongo.Conn.Model(req_data.Model).Filter(bson.M{
		"_id": req_data.Id,
	}).UpdateOne(req_data.Maps)
	return err
}

func GetPage(req_data *RequestData) ([]bson.M, int64, error) {
	result := []bson.M{}
	field_map, field_show_list, err := getFieldMapList(req_data)
	if err != nil {
		return result, 0, err
	}
	sort_str := ""
	if req_data.Params.Sort != "" && req_data.Params.Order != "" {
		if req_data.Params.Sort == "desc" {
			sort_str += "-" + req_data.Params.Order
		} else {
			sort_str += req_data.Params.Order
		}
	}
	if req_data.Params.Page <= 0 {
		req_data.Params.Page = 1
	}
	if req_data.Params.Size <= 0 {
		req_data.Params.Size = 20
	}
	query := bson.M{}
	for key, value := range req_data.Datas {
		if strings.HasSuffix(key, "_id") {
			query[key], _ = primitive.ObjectIDFromHex(value.(string))
		} else if utils.InArrayString([]string{"created", "updated", "deleted"}, key) {
			value_list := strings.Split(value.(string), ",")
			if len(value_list) == 2 {
				query[key] = bson.M{"$gte": value_list[0], "$lte": value_list[1]}
			} else if len(value_list) == 1 {
				query[key] = value
			}
		} else {
			query[key] = bson.M{"$regex": value, "$options": "i"}
		}
	}
	err = mongo.Conn.Model(req_data.Model).Select(field_show_list...).Filter(query).Skip(
		(req_data.Params.Page - 1) * req_data.Params.Size,
	).Limit(req_data.Params.Size).Sort(sort_str).Find(&result)
	if err != nil {
		return result, 0, err
	}
	total, err := mongo.Conn.Model(req_data.Model).Select(field_show_list...).Filter(query).Count()
	if err != nil {
		return result, 0, err
	}
	result, err = getRelatedData(result, field_map)
	if err != nil {
		return result, total, err
	}
	return result, total, nil
}

func GetList(req_data *RequestData) ([]bson.M, error) {
	result := []bson.M{}
	err := mongo.Conn.Model(req_data.Model).Filter(bson.M{}).Find(&result)
	return result, err
}

func GetListForSelect(req_data *RequestData) ([]bson.M, error) {
	result := []bson.M{}
	field_list, err := GetFieldList(req_data)
	if err != nil {
		return result, err
	}
	select_keys := []string{}
	label_list := []string{}
	value := ""
	for _, v := range field_list {
		field := v["field"].(string)
		select_value := v["select"]
		if select_value != nil {
			select_value_list := strings.Split(select_value.(string), ",")
			if len(select_value_list) != 0 {
				if field != "_id" {
					select_keys = append(select_keys, field)
				}
				for _, field_value := range select_value_list {
					if field_value == "label" {
						label_list = append(label_list, field)
					} else if field_value == "value" {
						value = field
					}
				}
			}
		}
	}
	new_result := []bson.M{}
	err = mongo.Conn.Model(req_data.Model).Select(select_keys...).Filter(bson.M{}).Find(&result)
	if err != nil {
		return new_result, err
	}
	for _, v := range result {
		label_value := ""
		for _, l := range label_list {
			if v[l] != nil {
				if label_value == "" {
					label_value = v[l].(string)
				} else {
					label_value += " - " + v[l].(string)
				}
			}
		}
		new_result = append(new_result, bson.M{
			"value": v[value],
			"label": label_value,
		})
	}
	return new_result, err
}

func GetFieldList(req_data *RequestData) ([]bson.M, error) {
	result := []bson.M{}
	err := mongo.Conn.Model("fields").Filter(bson.M{
		"model": req_data.Model,
	}).Find(&result)
	return result, err
}

func GetUpperList(req_data *RequestData) ([]bson.M, error) {
	fields := bson.M{}
	err := mongo.Conn.Model("fields").Filter(bson.M{
		"model":   req_data.Model,
		"is_bind": true,
	}).FindOne(&fields)
	if err != nil {
		return []bson.M{}, log.InfoReturn("没有设置key", err.Error())
	}
	result := []bson.M{}
	model_list := strings.Split(fields["bind"].(string), ".")
	if len(model_list) != 2 {
		return []bson.M{}, log.InfoReturn("model配置异常 len != 2")
	}
	if model_list[0] == consts.APP_NAME_RELATED {
		err = mongo.Conn.Model(model_list[1]).Filter(bson.M{}).Find(&result)
		return result, err
	} else {
		log.Warning("没写 - model配置异常")
		return result, nil
	}
}

func DeleteInfo(req_data *RequestData) error {
	return mongo.Conn.Model(req_data.Model).Filter(bson.M{
		"_id": req_data.Id,
	}).Delete(false)
}

// func WriteHideInfoList(req_data *RequestData, ids []string) error {
// 	opts := &options.UpdateOptions{}
// 	opts.SetUpsert(false)
// 	_, err := mongo.Conn.Collection(req_data.Model).UpdateMany(context.Background(), bson.M{
// 		"_id": bson.M{"$in": ids},
// 	}, opts)
// 	return err
// }

// func WriteDeleteInfo(req_data *RequestData) error {
// 	_, err := mongo.Conn.Collection(req_data.Model).DeleteOne(context.Background(), bson.M{
// 		"_id": req_data.Id,
// 	}, &options.DeleteOptions{})
// 	return err
// }

// func WriteDeleteInfoList(req_data *RequestData, ids []string) error {
// 	_, err := mongo.Conn.Collection(req_data.Model).DeleteMany(context.Background(), bson.M{
// 		"_id": bson.M{"$in": ids},
// 	}, &options.DeleteOptions{})
// 	return err
// }

// func ResponseInfo(ctx *gin.Context, errStr string, err error, req_data *RequestData) {
// 	log.Info(errStr, err.Error(), *req_data, *req_data.Params)
// 	ResResponse.Info(ctx, errStr)
// }

// func ResponseError(ctx *gin.Context, errStr string, err error, req_data *RequestData) {
// 	log.Error(errStr, err.Error(), *req_data, *req_data.Params)
// 	ResResponse.Error(ctx, errStr)
// }

// func ListFunc(req_data *RequestData) ([]bson.M, error) {
// 	result := []bson.M{}
// 	opts := &options.FindOptions{}
// 	cur, err := mongo.Conn.Collection(req_data.Model).Find(context.Background(), bson.M{
// 		"deleted": nil,
// 	}, opts)
// 	if err != nil {
// 		return result, err
// 	}
// 	err = cur.All(context.Background(), &result)
// 	return result, err
// }
